/**
 * 这个类，只放一些往后台请求服务的类
 * Create by 少凡
 * 2018/6/12
 */
import {PageHelper} from '../../utils/page-helper-model';
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {catchError, retry} from 'rxjs/operators';
import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
import {Consts} from '../../config/consts';
import {LayerService} from './layer.service';
import {ZorroService} from "./zorro.service";

@Injectable({
  providedIn: 'root'
})
export class BaseService {
  ws: WebSocket;
  constructor(public http: HttpClient,
              public layer: LayerService,
              public zorro: ZorroService
  ) {
  }

  /**
   * 新增方法
   * @param url
   * @param body
   * @returns {Observable<R|T>}
   */
  post(url: string, body: any): Observable<any> {
    return this.http.post(url, body, {headers: this.getHeaders()})
      .pipe(
        retry(1),
        catchError(error => this.handleError)
      );
  }


  post2(url: string, body: any): Observable<any> {
    return this.http.post(url, body)
      .pipe(
        retry(1),
        catchError(error => this.handleError)
      );
  }

  /**
   * 查询方法, 这个方法，可以查询单个对象，也可以果查询一个List
   * 查询单个对象时，可以传入url=/api/user/1, id可以不传，也可以传入url=/api/user, id=1查询单个对象
   * 查询List 传入url=/api/user/list,
   * @param url
   * @param id
   */
  get(url: string, id?: any): Observable<any> {
    if (id) {
      url = url + '/' + id
    }
    return this.http.get(url, {headers: this.getHeaders()})
      .pipe(
        retry(1),
        catchError(error => this.handleError)
      );
  }


  /**
   * 删除方法
   * @param url
   * @returns {Observable<R|T>}
   */
  delete(url: string, id: any): Observable<any> {
    return this.http.delete(url + '/' + id, {headers: this.getHeaders()})
      .pipe(
        retry(1),
        catchError(error => this.handleError)
      );
  }

  /**
   * 批量删除方法，body 可以是一个List<id>集合
   * @param url
   * @returns {Observable<R|T>}
   */
  deleteAll(url: string, body: any): Observable<any> {
    return this.http.post(url, body, {headers: this.getHeaders()})
      .pipe(
        retry(1),
        catchError(error => this.handleError)
      );
  }

  /**
   * 修改方法
   * @param url
   * @param body
   * @returns {Observable<R|T>}
   */
  put(url: string, body: any): Observable<any> {
    return this.http.put(url, body, {headers: this.getHeaders()})
      .pipe(
        retry(1),
        catchError(error => this.handleError)
      );
  }

  /**
   * 获取列表，带分页 多条件组合
   * 例 name = '张三' and sex = '男' and state = 1
   * @param {string} url
   * @param conditions
   * @param {PageHelper} pageHelp
   * @returns {Observable<any>}
   */
  findListByMuchCondition(url: string, conditions: any, pageHelper?: PageHelper) {
    if (pageHelper) {
      url = url + '?keyword=' + pageHelper.keyword + '&pageNum=' + pageHelper.currentPage + '&pageSize=' + pageHelper.pageSize;
    }
    return this.post(url, conditions);
  }

  /**
   * 获取列表，带分页和关键字
   * 例 userName = keyword or mobile = keyword
   * @param {string} url
   * @param {PageHelper} pageHelp
   * @returns {Observable<any>}
   */
  findListByKeyword(url: string, pageHelper: PageHelper): Observable<any> {
    url = url + '?keyword=' + pageHelper.keyword + '&pageNum=' + pageHelper.currentPage + '&pageSize=' + pageHelper.pageSize;
    return this.get(url);
  }

  /** resolve成功，reject错误
   * promise((resolve)=>{}) 封装同步调用
   * */
  promise(callback?: any) {
    return new Promise((resolve, reject) => {
      callback && callback(resolve, reject);
    });
  }

  /**
   * 添加头部Authorization信息
   * @returns {HttpHeaders}
   */
  private getHeaders(): HttpHeaders {
    let token = sessionStorage.getItem(Consts.ACCESS_TOKEN);
    return new HttpHeaders().set('Authorization', 'bearer ' + token);
  }

  /**
   * 错误捕获器
   * @param {HttpErrorResponse} error
   * @returns {throwError}
   */
  handleError = (error: HttpErrorResponse) => {
    if (error.error instanceof ErrorEvent) {
      // 出现客户端或网络错误。相应地处理它
      console.error('发生错误: ', error.error.message);
    } else {
      // 后端返回一个不成功的响应代码
      // 反应体可能包含错误的线索,
      if (error.status == 401) {
        this.layer.modal.closeAll();
        window.location.href = '/#/login';
        console.log('您还没有登录！或登录过期');
      }
      if (error.status == 403) {
        console.log('您访问的链接未获授权');
        this.layer.modal.closeAll();
        window.location.href = '/#/error/403';
      }
      if (error.status == 404) {
        console.log('您访问的链接不存在');
        this.layer.modal.closeAll();
        window.location.href = '/#/error/404';
      }
      console.error(
        `后端返回代码： ${error.status}, ` +
        `错误信息是:  ${error.error}`);
    }
    // 使用用户面临的错误消息返回可观察到的信息
    return console.error('服务器发生错误 ，请稍后重试！');
  };

  /**
   * 获取数据后的分页处理方法
   * @param data
   * @param pageHelp
   * @param list
   * @param error 自定义错误信息
   */
  pageHandle(data: any, pageHelper: PageHelper, succeed?: string, error?: string) {
    let list;
    if (data.status == 0) {
      list = data.data.list;
      pageHelper.totalItems = data.data.total;
    } else {
      list = null;
      // 设置当前页码
      pageHelper.currentPage = 1;
      // 设置总记录行数
      pageHelper.totalItems = 1;
      this.getResponse(data, succeed, error);
    }
    return {list: list, pageHelper: pageHelper};
  }

  /**
   * 请求返回的数据处理
   * @param data
   * @param error 自定义错误信息
   */
  getResponse(data: any, succeed?: string, error?: string) {
    let resultData;
    if (data.status == 0) {
      resultData = data.data;
      if (succeed != null) {
        this.layer.messageSuccess(succeed);
      } else {
        this.layer.messageSuccess(data.msg ? data.msg : '操作成功');
      }
    } else {
      if (error != null) {
        this.layer.messageError(error);
      } else {
        this.layer.messageError(data.msg ? data.msg : '操作失败');
      }
      return false;
    }
    return resultData;
  }

  createObservableSocket(url: string): Observable<any> {
    this.ws = new WebSocket(url);
    return new Observable(
      observer => {
        this.ws.onmessage = (event) => observer.next(event.data);
        this.ws.onerror = (event) => observer.error(event);
        this.ws.onclose = (event) => observer.complete();
      });
  }

}
